// Copyright 2011, Vanya Davidenko.
// Кодировка файла: UTF-8.
package info.iu9.red;



class DotStateVisitor implements StateVisitor {
  public DotStateVisitor(final FiniteAutomata fa) {
    fa_ = fa;
    sb_ = new StringBuilder();
  }

  String visitAll() {
    reset();

    sb_.append("digraph fa {\n");
    sb_.append("    rankdir = LR\n");
    for ( final State s : fa_ ) {
      s.accept(this);
      current_state_id_++;
    }
    sb_.append("}\n");
    return sb_.toString();
  }


  public void visit(final MatchState s) {
    add("Match", "", "doublecircle");
  }

  public void visit(final JumpState s) {
  }
  public void visit(final ForkState s) {
    final StringBuilder sb = new StringBuilder();
    sb.append(current_state_id_);
    sb.append(" -> ");
    sb.append(skipJumps(current_state_id_ + s.next()));
    sb.append("; ");
    sb.append(current_state_id_);
    sb.append(" -> ");
    sb.append(skipJumps(current_state_id_ + s.next_low()));

    sb.append(" [ style = dashed ];");
    add("Fork", sb.toString(), defaultShape());
  }

  public void visit(final BeginSaveState s) {
    addCommandState("Save" + String.valueOf(s.submatch_num()));
  }
  public void visit(final EndSaveState s) {
    addCommandState("/Save" + String.valueOf(s.submatch_num()));
  }

  public void visit(final BeginningAnchorState s) { addCommandState("^"); }
  public void visit(final EndOfStringAnchorState s) { addCommandState("\\\\z"); }
  public void visit(final EndingAnchorState s) { addCommandState("$"); }
  public void visit(final ReverseEndingAnchorState s) { addCommandState("Rev$"); }
  public void visit(final StringBeginningAnchorState s) { addCommandState("\\\\A"); }
  public void visit(final StringEndingAnchorState s) { addCommandState("\\\\Z"); }
  public void visit(final MultiLineBeginningAnchorState s) { addCommandState("^\\nML"); }
  public void visit(final MultiLineEndingAnchorState s) { addCommandState("$\\nML"); }
  public void visit(final WordBoundaryAnchorState s) { addCommandState("\\\\b"); }
  public void visit(final InvertedWordBoundaryAnchorState s) { addCommandState("\\\\B"); }

  public void visit(final DotState s) { addRegularState("Dot", "<any except \\\\n>"); }
  public void visit(final DotAllState s) { addRegularState("DotAll", "<any>"); }
  public void visit(final CharacterState s) { addRegularState("Char", s.toString()); }
  public void visit(final CaseCharacterState s) { addRegularState("Char", s.toString()); }
  public void visit(final CharacterGroupState s) { addRegularState("Char\\ngroup", s.toString()); }
  public void visit(final CaseCharacterGroupState s) { addRegularState("Char\\ngroup",  s.toString()); }


  private void reset() {
    current_state_id_ = 0;
    sb_.setLength(0);
  }

  private void add(final String label,
                   final String transitions,
                   final String shape) {
    sb_.append("    ");
    sb_.append(current_state_id_);
    sb_.append(" [ width = 0.75 fixedsize = true label = \"");
    sb_.append(label);
    sb_.append("\" shape = ");
    sb_.append(shape);
    sb_.append(" ]; ");
    sb_.append(transitions);
    sb_.append('\n');
  }


  private String defaultTransition(final String transition_label) {
    final StringBuilder sb = new StringBuilder();
    sb.append(current_state_id_);
    sb.append(" -> ");
    sb.append(skipJumps(current_state_id_ + 1));
    sb.append(" [ label = \"");
    sb.append(transition_label);
    sb.append("\" ]; ");
    return sb.toString();
  }

  private static String defaultShape() {
    return "circle";
  }

  private int skipJumps(final int state_id) {
    int next_state_id = state_id;
    for ( ; ; ) {
      final State s = fa_.get(next_state_id);
      if ( !(s instanceof JumpState) ) {
        return next_state_id;
      }
      next_state_id += ((JumpState)s).next();
    }
  }


  private void addCommandState(final String label) {
    add(label, defaultTransition(""), defaultShape());
  }

  private void addRegularState(final String label,
                               final String transitions_label) {
    add(label, defaultTransition(transitions_label), defaultShape());
  }

  private final FiniteAutomata fa_;
  private int current_state_id_;
  private final StringBuilder sb_;
}
